/* Douban API Javascript Library 0.2

Copyright (2007) Douban Inc.  All rights reserved.

Some code is copied from jQuery 1.2.1 ( by John Resig ) which is licensed under the MIT license.
*/

(function(){
    var isFunction = function( fn ) {
        return !!fn && typeof fn != "string" && !fn.nodeName &&
            fn.constructor != Array && /function/i.test( fn + "" );
    }
    var buildURL = function(url, params){
        var tmp = url.split("?");
        var uri = tmp[0];
        var ps = null;
        if (tmp.length > 1) ps = tmp[1].split("&");
        var pnames = uri.match(/{\w+}/g);
        if (pnames != null) {
            for (var i=0; i<pnames.length; ++i){
                var pn = pnames[i];
                var ppn = pnames[i].match(/{(\w+)}/)[1];
                if (!params[ppn]) return null;
                else uri = uri.replace(pn, params[ppn]);
            }
        }
        if (!ps) return uri;
        var re_ps = [];
        for (var i=0; i<ps.length; ++i) {
            var tmp = ps[i].match(/{(\w+)}/);
            if (tmp==null) re_ps.push(ps[i]);
            else {
                var pn = tmp[0];
                var ppn = tmp[1];
                if (params[ppn]) re_ps.push(encodeURI(ps[i].replace(pn, params[ppn])));
            }
        }
        if (re_ps.length>0) return [uri, re_ps.join("&")].join("?");
        else return uri;
    }
    var jsc = (new Date).getTime();
    var buildTempFunction = function(cb){
        var jsonp = "jsonp" + jsc++;
        window[ jsonp ] = function(data){
            cb(data);
            // Garbage collect
            window[ jsonp ] = undefined;
            try{ delete window[ jsonp ]; } catch(e){}
        };
        return jsonp;
    }
    var sendScriptRequest = function(url){
        var head = document.getElementsByTagName("head")[0];
        var script = document.createElement("script");
        script.src = url;
        script.charset = 'utf-8';
        head.appendChild(script);
    }
    var formatParams = function(params) {
        if (isFunction(params.callback)) params.callback = buildTempFunction(params.callback);
        if (!params.apikey) params.apikey = api_obj.apikey;
        return params;
    }
    var send = function(url, params){
        var url = buildURL(url, params);
        if (url!=null) sendScriptRequest(url);
    }

    var apikey = '';
    var namespace = 'DOUBAN';
    var obj = {
        apikey:apikey
    };
    var baseUri = 'http://api.douban.com/';
    var pp = 'start-index={startindex}&max-results={maxresults}';
    var sp = 'q={keyword}&'+pp;
    var pubp = 'published-min={publishedmin}&published-max={publishedmax}';
    var updp = 'updated-min={updatedmin}&updated-max={updatedmax}';
    var pup = pubp+'&'+updp;
    var ratp = 'rating-min={ratingmin}&rating-max={ratingmax}';
    var cp = 'apikey={apikey}&alt=xd&callback={callback}';
    var apis = {
        getUser: {url:baseUri+'people/{id}'},
        searchUsers: {url:baseUri+'people?'+sp},
        getBook: {url:baseUri+'book/subject/{id}'},
        getISBNBook: {url:baseUri+'book/subject/isbn/{isbn}'},
        searchBooks: {url:baseUri+'book/subjects?tag={tag}&'+sp},
        getMovie: {url:baseUri+'movie/subject/{id}'},
        searchMovies: {url:baseUri+'movie/subjects?tag={tag}&'+sp},
        getMusic: {url:baseUri+'music/subject/{id}'},
        searchMusic: {url:baseUri+'music/subjects?tag={tag}&'+sp},
        getReview: {url:baseUri+'review/{id}'},
        getUserReviews: {url:baseUri+'people/{uid}/reviews?'+pup+'&'+pp},
        getBookReviews: {url:baseUri+'book/subject/{sid}/reviews?'+pup+'&'+pp},
        getISBNBookReviews: {url:baseUri+'book/subject/isbn/{isbn}/reviews?'+pup+'&'+pp},
        getMovieReviews: {url:baseUri+'movie/subject/{sid}/reviews?'+pup+'&'+pp},
        getMusicReviews: {url:baseUri+'music/subject/{sid}/reviews?'+pup+'&'+pp},
        getCollection: {url:baseUri+'people/{uid}/collection/{cid}'},
        getUserCollection: {url:baseUri+'people/{uid}/collection?cat={cat}&tag={tag}&status={status}&'+updp+'&'+ratp+'&'+pp},
        getBookTags: {url:baseUri+'book/subject/{id}/tags?'+pp},
        getISBNBookTags: {url:baseUri+'book/subject/isbn/{isbn}/tags?'+pp},
        getMovieTags: {url:baseUri+'movie/subject/{id}/tags?'+pp},
        getMusicTags: {url:baseUri+'music/subject/{id}/tags?'+pp},
        getUserBookTags: {url:baseUri+'people/{id}/tags?cat=book&'+pp},
        getUserMovieTags: {url:baseUri+'people/{id}/tags?cat=movie&'+pp},
        getUserMusicTags: {url:baseUri+'people/{id}/tags?cat=music&'+pp}
    };
    for (var name in apis)
        if (apis[name].url.search(/\?/)!=-1) apis[name].url = apis[name].url + '&' + cp;
        else apis[name].url = apis[name].url + '?' + cp;

    //Set Global Values
    if (!window[namespace]) window[namespace] = {}
    var api_obj = window[namespace]; //a Temp Reference
    for (var name in obj) api_obj[name] = obj[name];
    for (var name in apis)
        api_obj[name] = (function(url){
            return function(params){
                send(url, formatParams(params));
            };
        })(apis[name].url)
})();

(function(){
	var namespace = 'DOUBAN';
	if (!window[namespace]) window[namespace] = {}
	var api_obj = window[namespace]; //a Temp Reference

	var parseElement = function(source, target, tagName, targetTagName) {
	    if (targetTagName==null) targetTagName = tagName;
	    if (source[tagName]) target[targetTagName] = source[tagName].$t
	}
	var parseRating = function(source, target) {
	    if (!source['gd:rating']) return;
	    target.rating = {
	        min:parseInt(source['gd:rating']['@min']),
	        numRaters:parseInt(source['gd:rating']['@numRaters']),
	        average:parseFloat(source['gd:rating']['@average']),
	        max:parseInt(source['gd:rating']['@max']),
	        value:parseInt(source['gd:rating']['@value'])
	    };
	}
	var parseAuthor = function(source, target) {
	    target.author={}
	    if (!source.author || !source.author[0]) return;
	    parseElement(source.author[0], target.author, 'name');
	    parseLinks(source.author[0], target.author);
	}
	var parseLinks = function(source, target) {
	    target.link = {};
	    if (source.link)
	        for (var i=0; i<source.link.length; ++i)
	            target.link[source.link[i]['@rel']] = source.link[i]['@href'];
	}
	var parseId = function(source, target) {
	    if (source.id) {
	        target.id=source.id.$t;
	        var tmp = target.id.split('/').slice(-1);
	        if (tmp.length > 0) target.nid = tmp[0]
	    }
	}
	var parseOpenSearch = function(source, target){
	    parseElement(source, target, 'opensearch:startIndex', 'startIndex');
	    target.startIndex = parseInt(target.startIndex)
	    parseElement(source, target, 'opensearch:itemPerPage', 'itemPerPage');
	    target.itemPerPage = parseInt(target.itemPerPage)
	    parseElement(source, target, 'opensearch:totalResults', 'totalResults');
	    target.totalResults = parseInt(target.totalResults)
	}
	var parseFeed = function(results, feed, entryParser){
	    parseOpenSearch(results, feed)
	    parseElement(results, feed, 'title')
	    feed.entries = []
	    for (var i=0; i<results.entry.length; ++i)
	        feed.entries.push(entryParser(results.entry[i]));
	}

	api_obj.parseUser = function(re) {
	    var user = {};
	    parseId(re, user)
	    parseElement(re, user, 'title');
	    if (user.title) user.name = user.title
	    parseElement(re, user, 'content');
	    parseElement(re, user, 'db:location', 'location');
	    parseLinks(re, user)
	    return user;
	}
	api_obj.parseUsers = function(results){
	    var feed = {};
	    parseFeed(results, feed, api_obj.parseUser)
	    return feed;
	}

	api_obj.parseSubject = function(re) {
	    var subject = {};
	    parseId(re, subject)
	    parseAuthor(re, subject)
	    parseElement(re, subject, 'title');
	    parseElement(re, subject, 'summary');
	    parseRating(re, subject);
	    parseLinks(re, subject)
	    if (re.category) subject.category  = re.category['@term'].match('2007#([a-z]+)')[1];
	    subject.tag = [];
	    if (re['db:tag'])
	        for (var j=0; j<re['db:tag'].length; ++j)
	            subject.tag.push({count:parseInt(re['db:tag'][j]['@count']), name:re['db:tag'][j]['@name']});
	    subject.attribute = {};
	    if (re['db:attribute'])
	        for (var j=0; j<re['db:attribute'].length; ++j) {
	            if (subject.attribute[re['db:attribute'][j]['@name']] == null)
	                subject.attribute[re['db:attribute'][j]['@name']] = [];
	            subject.attribute[re['db:attribute'][j]['@name']].push(re['db:attribute'][j]['$t']);
	            if (re['db:attribute'][j]['@name'] == 'aka' && re['db:attribute'][j]['@lang'] == 'zh_CN')
	                subject.title_cn = re['db:attribute'][j]['$t']
	        }
	    return subject;
	}
	api_obj.parseSubjects = function(results){
	    var feed = {};
	    parseFeed(results, feed, api_obj.parseSubject)
	    return feed;
	}

	api_obj.parseReview = function(re) {
	    var review = {};
	    parseId(re, review)
	    parseAuthor(re, review)
	    parseElement(re, review, 'title');
	    parseElement(re, review, 'summary');
	    parseElement(re, review, 'published');
	    parseElement(re, review, 'updated')
	    parseRating(re, review);
	    parseLinks(re, review)
	    if (re['db:subject']) review.subject = api_obj.parseSubject(re['db:subject'])
	    return review;
	}
	api_obj.parseReviews = function(results){
	    var feed = {}
	    parseAuthor(results, feed)
	    if (results['db:subject']) feed.subject = api_obj.parseSubject(results['db:subject'])
	    parseFeed(results, feed, api_obj.parseReview)
	    return feed;
	}

	api_obj.parseCollection = function(re) {
	    var collection = {};
	    parseId(re, collection)
	    parseElement(re, collection, 'title');
	    parseElement(re, collection, 'summary');
	    parseElement(re, collection, 'updated')
	    parseElement(re, collection, 'db:status', 'status')
	    parseRating(re, collection);
	    parseLinks(re, collection)
	    collection.tag = [];
	    if (re['db:tag'])
	        for (var j=0; j<re['db:tag'].length; ++j)
	            collection.tag.push({name:re['db:tag'][j]['@name']});
	    if (re['db:subject']) collection.subject = api_obj.parseSubject(re['db:subject'])
	    return collection;
	}
	api_obj.parseMultiCollection = function(results) {
	    var feed = {}
	    parseAuthor(results, feed)
	    parseFeed(results, feed, api_obj.parseCollection)
	    return feed;
	}

	api_obj.parseTag = function(re){
	    var tag = {};
	    parseElement(re, tag, 'id');
	    if (tag.title) tag.name = tag.title
	    parseElement(re, tag, 'title');
	    parseElement(re, tag, 'count')
	    return tag;
	}
	api_obj.parseTags = function(results){
	    var feed = {}
	    parseFeed(results, feed, api_obj.parseTag)
	    return feed
	}
	})();